home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 July / EnigmA AMIGA RUN 20 (1997)(G.R. Edizioni)(IT)[!][issue 1997-07 & 08][EAR-CD IV].iso / earcd / text / misc / nroff.lha / nroff / command.c next >
C/C++ Source or Header  |  1997-01-24  |  31KB  |  1,748 lines

  1. /*
  2.  *    command.c - command input parser/processor for nroff text processor
  3.  *
  4.  *    adapted for atariST/TOS by Bill Rosenkranz 11/89
  5.  *    net:    rosenkra@hall.cray.com
  6.  *    CIS:    71460,17
  7.  *    GENIE:    W.ROSENKRANZ
  8.  *
  9.  *    original author:
  10.  *
  11.  *    Stephen L. Browning
  12.  *    5723 North Parker Avenue
  13.  *    Indianapolis, Indiana 46220
  14.  *
  15.  *    history:
  16.  *
  17.  *    - Originally written in BDS C;
  18.  *    - Adapted for standard C by W. N. Paul
  19.  *    - Heavily hacked up to conform to "real" nroff by Bill Rosenkranz
  20.  */
  21.  
  22. #undef NRO_MAIN                    /* extern globals */
  23.  
  24. #include <stdio.h>
  25. #include "nroff.h"
  26.  
  27. #define iscond(x)    ((x)=='>'||(x)=='<'||(x)=='=')
  28. #define isoper(x)    ((x)=='+'||(x)=='-'||(x)=='*'||(x)=='/'||(x)=='%')
  29.  
  30. /*------------------------------*/       
  31. /*    comand            */
  32. /*------------------------------*/       
  33. comand (p)
  34. register char  *p;
  35. {
  36.  
  37. /*
  38.  *    main command processor
  39.  */
  40.  
  41.     static int    in_if_cond = 0;
  42.  
  43.     register int    i;
  44.     register int    ct;
  45.     register int    val;
  46.     register int       indx;
  47.     int        newval;
  48.     int         spval;
  49.     int        not_cond;
  50.     char        argtyp;
  51.     char        name[MAXLINE];
  52.     char        macexp[MXMLEN];
  53.     int        tmp;
  54.     char           *pfs;
  55.     char        fs[20];
  56.     char        c;
  57.     char           *ps1;
  58.     char           *ps2;
  59.  
  60.  
  61.     if (debugging)
  62.         fprintf (err_stream,
  63.         "***%s.comand: enter, p=|%s|\n",myname,p);
  64.  
  65.     /*
  66.      *   get command code
  67.      */
  68.     ct = comtyp (p, macexp);
  69.  
  70.     /*
  71.      *   error?
  72.      */
  73.     if (ct == UNKNOWN)
  74.     {
  75.         fprintf (err_stream,
  76.             "***%s: unrecognized command %s\n", myname, p);
  77.         return;
  78.     }
  79.  
  80.     /*
  81.      *   ignore comments
  82.      */
  83.     if (ct == COMMENT)
  84.         return;
  85.  
  86.  
  87.     /*
  88.      *   do escape expansion on command line args
  89.      */
  90.     expesc (p, name);
  91.  
  92.  
  93.     /*
  94.      *   get value of command
  95.      */
  96. /*    val = getval (p, &argtyp);*/
  97.  
  98.  
  99.     /*
  100.      *   do the command
  101.      */
  102.     switch (ct)
  103.     {
  104.     /* set (¶m, val, type, defval, minval, maxval) */
  105.     case FC:
  106.         /*
  107.          *   field delim/pad chars
  108.          *
  109.          *   .fc [delim] [pad]
  110.          */
  111.         fprintf (err_stream, "***%s: .fc not available\n", myname);
  112.         break;
  113.     case TR:
  114.         /*
  115.          *   translate
  116.          *
  117.          *   .tr ab...
  118.          */
  119.         fprintf (err_stream, "***%s: .tr not available\n", myname);
  120.         break;
  121.  
  122.  
  123.  
  124.  
  125.     case AD:
  126.         /*
  127.          *   adjust
  128.          *
  129.          *   .ad [mode]
  130.          */
  131.         val = getval (p, &argtyp);
  132.         p = skipwd (p);
  133.         p = skipbl (p);
  134.  
  135.         switch (*p)
  136.         {
  137.         case 'l':
  138.             dc.adjval = ADJ_LEFT;
  139.             dc.juval  = YES;
  140.             break;
  141.         case 'r':
  142.             dc.adjval = ADJ_RIGHT;
  143.             dc.juval  = YES;
  144.             break;
  145.         case 'c':
  146.             dc.adjval = ADJ_CENTER;
  147.             dc.juval  = YES;
  148.             break;
  149.         case 'b':
  150.         case 'n':
  151.             dc.adjval = ADJ_BOTH;
  152.             dc.juval  = YES;
  153.             break;
  154.         default:
  155.             break;
  156.         }
  157.         break;
  158.     case AF:
  159.         /*
  160.          *   assign format to number reg
  161.          *
  162.          *   .af R {1,a,A,i,I,0...1}
  163.          */
  164.         val = getval (p, &argtyp);
  165.         p = skipwd (p);
  166.         p = skipbl (p);
  167.         if (!isalpha (*p))
  168.         {
  169.             fprintf (err_stream,
  170.                 "***%s: invalid or missing number register name\n",
  171.                 myname);
  172.         }
  173.         else
  174.         {
  175.             /*
  176.              *   number register format is 1,a,A,i,I,0...1
  177.              *   default is 1. for 0001 format, store num dig
  178.              *   or'ed with 0x80, up to 8 digits.
  179.              */
  180.             indx = tolower (*p) - 'a';
  181.             p = skipwd (p);
  182.             p = skipbl (p);
  183.             if (*p == '1')
  184.                 dc.nrfmt[indx] = '1';
  185.             else if (*p == 'a')
  186.                 dc.nrfmt[indx] = 'a';
  187.             else if (*p == 'A')
  188.                 dc.nrfmt[indx] = 'A';
  189.             else if (*p == 'i')
  190.                 dc.nrfmt[indx] = 'i';
  191.             else if (*p == 'I')
  192.                 dc.nrfmt[indx] = 'I';
  193.             else if (*p == '0')
  194.             {
  195.                 for (i = 0; isdigit (p[i]); i++)
  196.                     ;
  197.                 dc.nrfmt[indx] = (char) (i);
  198.                 if (dc.nrfmt[indx] <= 0)
  199.                     dc.nrfmt[indx] = '1';
  200.                 else if (dc.nrfmt[indx] > 8)
  201.                 {
  202.                     dc.nrfmt[indx]  = 8;
  203.                     dc.nrfmt[indx] |= 0x80;
  204.                 }
  205.                 else
  206.                     dc.nrfmt[indx] |= 0x80;
  207.  
  208.             }
  209.             else
  210.                 dc.nrfmt[indx] = '1';
  211.         }
  212.         break;
  213.     case BD:
  214.         /*
  215.          *   embolden font (IGNORED)
  216.          *
  217.          *   .bd [S] F N
  218.          */
  219.         break;
  220.     case BO:
  221.         /*
  222.          *   bold face
  223.          *
  224.          *   .bo [N]
  225.          */
  226.         val = getval (p, &argtyp);
  227.         set (&dc.boval, val, argtyp, 1, 0, HUGE);
  228.         dc.cuval = dc.ulval = 0;
  229.         break;
  230.     case BP:
  231.         /*
  232.          *   begin page
  233.          *
  234.          *   .bp [+/-N]
  235.          */
  236.         val = getval (p, &argtyp);
  237.         if (pg.lineno > 0)
  238.             space (HUGE);
  239.         set (&pg.curpag, val, argtyp, pg.curpag + 1, -HUGE, HUGE);
  240.         pg.newpag = pg.curpag;
  241.         set_ireg ("%", pg.newpag, 0);
  242.         break;
  243.     case BR:
  244.         /*
  245.          *   break (page)
  246.          *
  247.          *   .br
  248.          */
  249.         robrk ();
  250.         break;
  251.     case BS:
  252.         /*
  253.          *   backspc in output
  254.          *
  255.          *   .bs [N]
  256.          */
  257.         val = getval (p, &argtyp);
  258.         set (&dc.bsflg, val, argtyp, 1, 0, 1);
  259.         break;
  260.     case C2:
  261.         /*
  262.          *   nobreak char
  263.          *
  264.          *   .c2 [c=']
  265.          */
  266.         val = getval (p, &argtyp);
  267.         if (argtyp == '\r' || argtyp == '\n')
  268.             dc.nobrchr = '\'';
  269.         else
  270.             dc.nobrchr = argtyp;
  271.         break;
  272.     case CC:
  273.         /*
  274.          *   command character
  275.          *
  276.          *   .cc [c=.]
  277.          */
  278.         val = getval (p, &argtyp);
  279.         if (argtyp == '\r' || argtyp == '\n')
  280.             dc.cmdchr = '.';
  281.         else
  282.             dc.cmdchr = argtyp;
  283.         break;
  284.     case CE:
  285.         /*
  286.          *   center
  287.          *
  288.          *   .ce [N]
  289.          */
  290.         val = getval (p, &argtyp);
  291.         robrk ();
  292.         set (&dc.ceval, val, argtyp, 1, 0, HUGE);
  293.         break;
  294.     case CS:
  295.         /*
  296.          *   constant space char (IGNORED)
  297.          *
  298.          *   .cs F N M
  299.          */
  300.         break;
  301.     case CU:
  302.         /*
  303.          *   continuous underline
  304.          *
  305.          *   .cu [N]
  306.          */
  307.         val = getval (p, &argtyp);
  308.         set (&dc.cuval, val, argtyp, 1, 0, HUGE);
  309.         dc.ulval = dc.boval = 0;
  310.         break;
  311.     case DE:
  312.         /*
  313.          *   define macro
  314.          *
  315.          *   .de name [end]
  316.          */
  317.         val = getval (p, &argtyp);
  318.         ignoring = FALSE;
  319.         defmac (p, sofile[dc.flevel]);
  320.         break;
  321.     case DS:
  322.         /*
  323.          *   define string
  324.          *
  325.          *   .ds name string
  326.          */
  327.         val = getval (p, &argtyp);
  328.         defstr (p);
  329.         break;
  330.     case EC:
  331.         /*
  332.          *   escape char
  333.          *
  334.          *   .ec [c=\]
  335.          */
  336.         val = getval (p, &argtyp);
  337.         if (argtyp == '\r' || argtyp == '\n')
  338.             dc.escchr = '\\';
  339.         else
  340.             dc.escchr = argtyp;
  341.         dc.escon = YES;
  342.         break;
  343.     case EF:
  344.         /*
  345.          *   even footer
  346.          *
  347.          *   .ef "a" "b" "c"
  348.          */
  349.         val = getval (p, &argtyp);
  350.         gettl (p, pg.efoot, &pg.eflim[0]);
  351.         break;
  352.     case EH:
  353.         /*
  354.          *   even header
  355.          *
  356.          *   .eh "a" "b" "c"
  357.          */
  358.         val = getval (p, &argtyp);
  359.         gettl (p, pg.ehead, &pg.ehlim[0]);
  360.         break;
  361.     case EN:
  362.         /*
  363.          *   end macro def (should not get one here...)
  364.          *
  365.          *   .en or ..
  366.          */
  367.         fprintf (err_stream, "***%s: missing .de command\n", myname);
  368.         break;
  369.     case EO:
  370.         /*
  371.          *   escape off
  372.          *
  373.          *   .eo
  374.          */
  375.         dc.escon = NO;
  376.         break;
  377.     case EX:
  378.         /*
  379.          *   exit
  380.          *
  381.          *   .ex
  382.          */
  383.         if (sofile[0] != stdin)
  384.             fclose (sofile[0]);
  385.         for (i = 1; i <= Nfiles; i++)
  386.         {
  387.             if (sofile[i] != NULL_FPTR)
  388.                 fclose (sofile[i]);
  389.         }
  390.         err_exit (0);
  391.         break;
  392.     case FI:
  393.         /*
  394.          *   fill
  395.          *
  396.          *   .fi
  397.          */
  398.         robrk ();
  399.         dc.fill = YES;
  400.         break;
  401.     case FL:
  402.         /*
  403.          *   flush NOW
  404.          *
  405.          *   .fl
  406.          */
  407.         fflush (out_stream);
  408.         break;
  409.     case FO:
  410.         /*
  411.          *   footer
  412.          *
  413.          *   .fo "a" "b" "c"
  414.          */
  415.         val = getval (p, &argtyp);
  416.         gettl (p, pg.efoot, &pg.eflim[0]);
  417.         gettl (p, pg.ofoot, &pg.oflim[0]);
  418.         break;
  419.     case FT:
  420.         /*
  421.          *   font change
  422.          *
  423.          *   .ft {R,I,B,S,P}
  424.          *
  425.          *   the way it's implemented here, it causes a break
  426.          *   rather than be environmental...
  427.          */
  428.         val = getval (p, &argtyp);
  429.         p = skipwd (p);
  430.         p = skipbl (p);
  431.         if (!isalpha (*p))
  432.         {
  433.             fprintf (err_stream,
  434.                 "***%s: invalid or missing font name\n",
  435.                 myname);
  436.         }
  437.         else
  438.         {
  439.             pfs = &fs[0];
  440.  
  441.             fontchange (*p, pfs);
  442.  
  443.             robrk ();
  444.             fflush (out_stream);
  445.             fprintf (out_stream, "%s", pfs);
  446.             fflush (out_stream);
  447.         }
  448.         break;
  449.     case TL:
  450.     case HE:
  451.         /*
  452.          *   header (both are currently identical. .he is -me)
  453.          *
  454.          *   .tl "a" "b" "c"
  455.          *   .he "a" "b" "c"
  456.          */
  457.         val = getval (p, &argtyp);
  458.         gettl (p, pg.ehead, &pg.ehlim[0]);
  459.         gettl (p, pg.ohead, &pg.ohlim[0]);
  460.         break;
  461.     case IE:
  462.         /*
  463.          *   if of if/else conditional
  464.          *
  465.          *   .ie condition anything
  466.          *   .el anything
  467.          *
  468.          *   .ie condition \{\
  469.          *   ...
  470.          *   ... \}
  471.          *   .el \{\
  472.          *   ...
  473.          *   ... \}
  474.          */
  475.         fprintf (err_stream, "***%s: .ie not available\n", myname);
  476.         break;
  477.     case EL:
  478.         /*
  479.          *   else of if/else conditional
  480.          *
  481.          *   .ie condition anything
  482.          *   .el anything
  483.          *
  484.          *   .ie condition \{\
  485.          *   ...
  486.          *   ... \}
  487.          *   .el \{\
  488.          *   ...
  489.          *   ... \}
  490.          */
  491.         fprintf (err_stream, "***%s: .el not available\n", myname);
  492.         break;
  493.     case IF:
  494.         /*
  495.          *   conditional
  496.          *
  497.          *   .if c command        [c=n(roff),t(roff),e(ven),o(dd)]
  498.          *   .if !c command
  499.          *   .if 's1's2' command    [s1 == s2]
  500.          *   .if !'s1's2' command    [s1 != s2]
  501.          *   .if N command        [N > 0]
  502.          *   .if !N command        [N <= 0]
  503.          *
  504.          *   .if cond \{\
  505.          *   command
  506.          *   ... \}
  507.          */
  508.         p = skipwd (p);
  509.         p = skipbl (p);
  510.         not_cond = 0;
  511.         if (*p == '!')
  512.         {
  513.             p++;
  514.             not_cond = 1;
  515.         }
  516.         if (islower (*p) && isspace (*(p+1)))
  517.         {
  518.             /*
  519.              *   single char: n=nroff,t=troff,e=evenpage,o=oddpage
  520.              */
  521.             c = *p;
  522.             switch (c)
  523.             {
  524.             case 'n':        /* if nroff... (always T) */
  525.                 p = skipwd (p);
  526.                 p = skipbl (p);
  527.  
  528.                 if (debugging)
  529.                     fprintf (err_stream,
  530.                     "***%s.comand: p=|%s|\n",myname, p);
  531.  
  532.                 if (*p != EOS && not_cond == 0)
  533.                 {
  534.                     if (*p == '\\' && *(p+1) == '{')
  535.                     {
  536.                         read_if ();
  537.                     }
  538.                     else
  539.                     {
  540.                         if (*p == dc.cmdchr)
  541.                              comand (p);
  542.                         else
  543.                         {
  544.                             if (*p == '\"')
  545.                                 p++;
  546.                             if (*p == ' ')
  547.                                 robrk ();
  548.                             text (p);
  549.                         }
  550.                     }
  551.                 }
  552.                 break;
  553.             case 't':        /* if troff... (always F) */
  554.                 p = skipwd (p);
  555.                 p = skipbl (p);
  556.  
  557.                 if (debugging)
  558.                     fprintf (err_stream,
  559.                     "***%s.comand: p=|%s|\n",myname, p);
  560.  
  561.                 if (*p != EOS && not_cond != 0)
  562.                 {
  563.                     if (*p == '\\' && *(p+1) == '{')
  564.                     {
  565.                         read_if ();
  566.                     }
  567.                     else
  568.                     {
  569.                         if (*p == dc.cmdchr)
  570.                              comand (p);
  571.                         else
  572.                         {
  573.                             if (*p == '\"')
  574.                                 p++;
  575.                             if (*p == ' ')
  576.                                 robrk ();
  577.                             text (p);
  578.                         }
  579.                     }
  580.                 }
  581.                 break;
  582.             case 'e':        /* if even page... */
  583.                 p = skipwd (p);
  584.                 p = skipbl (p);
  585.  
  586.                 if (debugging)
  587.                     fprintf (err_stream,
  588.                     "***%s.comand: p=|%s|\n",myname, p);
  589.  
  590.  
  591.                 if (((pg.curpag % 2) == 0 && not_cond == 0)
  592.                 ||  ((pg.curpag % 2) != 0 && not_cond != 0))
  593.                 {        /* could be newpag, too */
  594.                     if (*p == '\\' && *(p+1) == '{')
  595.                     {
  596.                         read_if ();
  597.                     }
  598.                     else
  599.                     {
  600.                         if (*p == dc.cmdchr)
  601.                              comand (p);
  602.                         else
  603.                         {
  604.                             if (*p == '\"')
  605.                                 p++;
  606.                             if (*p == ' ')
  607.                                 robrk ();
  608.                             text (p);
  609.                         }
  610.                     }
  611.                 }
  612.                 break;
  613.             case 'o':        /* if odd page... */
  614.                 p = skipwd (p);
  615.                 p = skipbl (p);
  616.  
  617.                 if (debugging)
  618.                     fprintf (err_stream,
  619.                     "***%s.comand: p=|%s|\n",myname, p);
  620.  
  621.  
  622.                 if (((pg.curpag % 2) == 1 && not_cond == 0)
  623.                 ||  ((pg.curpag % 2) != 1 && not_cond != 0))
  624.                 {
  625.                     if (*p == '\\' && *(p+1) == '{')
  626.                     {
  627.                         read_if ();
  628.                     }
  629.                     else
  630.                     {
  631.                         if (*p == dc.cmdchr)
  632.                              comand (p);
  633.                         else
  634.                         {
  635.                             if (*p == '\"')
  636.                                 p++;
  637.                             if (*p == ' ')
  638.                                 robrk ();
  639.                             text (p);
  640.                         }
  641.                     }
  642.                 }
  643.                 break;
  644.             }
  645.         }
  646.         else if (*p == '\'' || *p == '/' || *p == '\"')
  647.         {
  648.             /*
  649.              *   compare strings. we need to interpolate here
  650.              */
  651.             c = *p;
  652.             ps1 = ++p;
  653.             while (*p != EOS && *p != c)
  654.                 p++;
  655.             *p = EOS;
  656.             ps2 = ++p;
  657.             while (*p != EOS && *p != c)
  658.                 p++;
  659.             *p = EOS;
  660.  
  661.             if (debugging)
  662.                 fprintf (err_stream,
  663.                 "***%s.comand: strcmp (ps1=|%s|,ps2=|%s|)\n",
  664.                 myname, ps1, ps2);
  665.  
  666.             if ((!strcmp (ps1, ps2) && not_cond == 0)
  667.             ||  ( strcmp (ps1, ps2) && not_cond != 0))
  668.             {
  669.                 p++;
  670.                 p = skipbl (p);
  671.  
  672.                 if (*p == '\\' && *(p+1) == '{')
  673.                 {
  674.                     read_if ();
  675.                 }
  676.                 else
  677.                 {
  678.                     if (*p == dc.cmdchr)
  679.                          comand (p);
  680.                     else
  681.                     {
  682.                         if (*p == '\"')
  683.                             p++;
  684.                         if (*p == ' ')
  685.                             robrk ();
  686.                         text (p);
  687.                     }
  688.                 }
  689.             }
  690.         }
  691.         else
  692.         {
  693.             /*
  694.              *   number
  695.              */
  696.  
  697.             if (debugging)
  698.                 fprintf (err_stream,
  699.                 "***%s.comand: p=|%s|\n",myname, p);
  700.  
  701.             val = getnumeric (p);
  702.             if ((val >  0 && not_cond == 0)
  703.             ||  (val <= 0 && not_cond != 0))
  704.             {
  705.                 p = skipwd (p);
  706.                 p = skipbl (p);
  707.  
  708.                 if (*p == '\\' && *(p+1) == '{')
  709.                 {
  710.                     read_if ();
  711.                 }
  712.                 else
  713.                 {
  714.                     if (*p == dc.cmdchr)
  715.                          comand (p);
  716.                     else
  717.                     {
  718.                         if (*p == '\"')
  719.                             p++;
  720.                         if (*p == ' ')
  721.                             robrk ();
  722.                         text (p);
  723.                     }
  724.                 }
  725.             }
  726.         }
  727.         break;
  728.     case IG:
  729.         /*
  730.          *   ignore input lines
  731.          *
  732.          *   .ig name
  733.          */
  734.         val = getval (p, &argtyp);
  735.         ignoring = TRUE;
  736.         defmac (p, sofile[dc.flevel]);
  737.         break;
  738.     case IN:
  739.         /*
  740.          *   indenting
  741.          *
  742.          *   .in [+/-N]
  743.          */
  744.         val = getval (p, &argtyp);
  745.         set (&dc.inval, val, argtyp, 0, 0, dc.rmval - 1);
  746.         set_ireg (".i", dc.inval, 0);
  747.         dc.tival = dc.inval;
  748.         break;
  749.     case JU:
  750.         /*
  751.          *   justify
  752.          *
  753.          *   .ju
  754.          */
  755.         dc.juval = YES;
  756.         break;
  757.     case LG:
  758.         /*
  759.          *   ligature (IGNORED)
  760.          *
  761.          *   .lg [N]
  762.          */
  763.         break;
  764.     case LL:
  765.         /*
  766.          *   line length
  767.          *
  768.          *   .ll [+/-N]
  769.          *   .rm [+/-N]
  770.          */
  771.         val = getval (p, &argtyp);
  772.         set (&dc.rmval, val, argtyp, PAGEWIDTH, dc.tival + 1, HUGE);
  773.         set (&dc.llval, val, argtyp, PAGEWIDTH, dc.tival + 1, HUGE);
  774.         set_ireg (".l", dc.llval, 0);
  775.         break;
  776.     case LS:
  777.         /*
  778.          *   line spacing
  779.          *
  780.          *   .ls [+/-N=+1]
  781.          */
  782.         val = getval (p, &argtyp);
  783.         set (&dc.lsval, val, argtyp, 1, 1, HUGE);
  784.         set_ireg (".v", dc.lsval, 0);
  785.         break;
  786.     case LT:
  787.         /*
  788.          *   title length
  789.          *
  790.          *   .lt N
  791.          */
  792.         val = getval (p, &argtyp);
  793.         set (&dc.ltval, val, argtyp, PAGEWIDTH, 0, HUGE);
  794.         pg.ehlim[RIGHT] = dc.ltval;
  795.         pg.ohlim[RIGHT] = dc.ltval;
  796.         break;
  797.     case M1:
  798.         /*
  799.          *   topmost margin
  800.          *
  801.          *   .m1 N
  802.          */
  803.         val = getval (p, &argtyp);
  804.         set (&pg.m1val, val, argtyp, 2, 0, HUGE);
  805.         break;
  806.     case M2:
  807.         /*
  808.          *   second top margin
  809.          *
  810.          *   .m2 N
  811.          */
  812.         val = getval (p, &argtyp);
  813.         set (&pg.m2val, val, argtyp, 2, 0, HUGE);
  814.         break;
  815.     case M3:
  816.         /*
  817.          *   1st bottom margin
  818.          *
  819.          *   .m3 N
  820.          */
  821.         val = getval (p, &argtyp);
  822.         set (&pg.m3val, val, argtyp, 2, 0, HUGE);
  823.         pg.bottom = pg.plval - pg.m4val - pg.m3val;
  824.         break;
  825.     case M4:
  826.         /*
  827.          *   bottom-most marg
  828.          *
  829.          *   .m4 N
  830.          */
  831.         val = getval (p, &argtyp);
  832.         set (&pg.m4val, val, argtyp, 2, 0, HUGE);
  833.         pg.bottom = pg.plval - pg.m4val - pg.m3val;
  834.         break;
  835.     case MACRO:
  836.         /*
  837.          *   macro expansion
  838.          *
  839.          *   (internal)
  840.          */
  841.         maceval (p, macexp);
  842.         break;
  843.     case MC:
  844.         /*
  845.          *   margin character (change bars)
  846.          *
  847.          *   .mc [c [N]]
  848.          *
  849.          *   right margin only, default 0.2i
  850.          */
  851.         val = getval (p, &argtyp);
  852.         if (argtyp == '\r' || argtyp == '\n')
  853.             mc_ing = FALSE;        /* turn off... */
  854.         else
  855.         {
  856.             mc_ing   = TRUE;    /* turn on... */
  857.             mc_space = 2;        /* force these for now... */
  858.             mc_char  = argtyp;    /* single char only!!! */
  859.  
  860.             p = skipwd (p);
  861.             p = skipbl (p);
  862.  
  863.             val = getval (p, &argtyp);
  864.             set (&mc_space, val, argtyp, 2, 0, dc.llval);
  865.         }
  866.         break;
  867.     case NA:
  868.         /*
  869.          *   no adjust
  870.          *
  871.          *   .na
  872.          */
  873.         dc.adjval = ADJ_OFF;
  874.         dc.juval  = NO;
  875.         break;
  876.     case NE:
  877.         /*
  878.          *   need n lines
  879.          *
  880.          *   .ne N
  881.          */
  882.         val = getval (p, &argtyp);
  883.         robrk ();
  884.         if ((pg.bottom - pg.lineno + 1) < (val * dc.lsval))
  885.         {
  886.             space (HUGE);
  887.         }
  888.         break;
  889.     case NF:
  890.         /*
  891.          *   no fill
  892.          *
  893.          *   .nf
  894.          */
  895.         robrk ();
  896.         dc.fill = NO;
  897.         break;
  898.     case NJ:
  899.         /*
  900.          *   no justify
  901.          *
  902.          *   .nj
  903.          */
  904.         dc.juval = NO;
  905.         break;
  906.     case NR:
  907.         /*
  908.          *   set number reg
  909.          *
  910.          *   .nr R +/-N M
  911.          */
  912.         val = getval (p, &argtyp);
  913.         p = skipwd (p);
  914.         p = skipbl (p);
  915.         if (!isalpha (*p))
  916.         {
  917.             fprintf (err_stream,
  918.                 "***%s: invalid or missing number register name\n",
  919.                 myname);
  920.         }
  921.         else
  922.         {
  923.             /*
  924.              *   indx is the register, R, and val is the final
  925.              *   value (default = 0). getval does skipwd,skipbl
  926.              */
  927.             indx = tolower (*p) - 'a';
  928.             val = getval (p, &argtyp);
  929.             set (&dc.nr[indx], val, argtyp, 0, -INFINITE, INFINITE);
  930.  
  931.             /*
  932.              *   now get autoincrement M, if any (default = 1).
  933.              *   getval does skipwd,skipbl
  934.              */
  935.             p = skipwd (p);
  936.             p = skipbl (p);
  937.             val = getval (p, &argtyp);
  938.             set (&dc.nrauto[indx], val, '1', 1, -INFINITE, INFINITE);
  939.         }
  940.         break;
  941.     case OF:
  942.         /*
  943.          *   odd footer
  944.          *
  945.          *   .of "a" "b" "c"
  946.          */
  947.         val = getval (p, &argtyp);
  948.         gettl (p, pg.ofoot, &pg.oflim[0]);
  949.         break;
  950.     case OH:
  951.         /*
  952.          *   odd header
  953.          *
  954.          *   .oh "a" "b" "c"
  955.          */
  956.         val = getval (p, &argtyp);
  957.         gettl (p, pg.ohead, &pg.ohlim[0]);
  958.         break;
  959.     case PC:
  960.         /*
  961.          *   page number char
  962.          *
  963.          *   .pc [c=NULL]
  964.          */
  965.         val = getval (p, &argtyp);
  966.         if (argtyp == '\r' || argtyp == '\n')
  967.             dc.pgchr = EOS;
  968.         else
  969.             dc.pgchr = argtyp;
  970.         break;
  971.     case PL:
  972.         /*
  973.          *   page length
  974.          *
  975.          *   .pl N
  976.          */
  977.         val = getval (p, &argtyp);
  978.         set (&pg.plval,
  979.              val,
  980.              argtyp,
  981.              PAGELEN,
  982.              pg.m1val + pg.m2val + pg.m3val + pg.m4val + 1,
  983.              HUGE);
  984.         set_ireg (".p", pg.plval, 0);
  985.         pg.bottom = pg.plval - pg.m3val - pg.m4val;
  986.         break;
  987.     case PM:
  988.         /*
  989.          *   print macro names and sizes
  990.          *
  991.          *   .pm [t]
  992.          */
  993.         val = getval (p, &argtyp);
  994.         if (argtyp == '\r' || argtyp == '\n')
  995.             printmac (0);
  996.         else if (argtyp == 't')
  997.             printmac (1);
  998.         else if (argtyp == 'T')
  999.             printmac (2);
  1000.         else
  1001.             printmac (0);
  1002.         break;
  1003.     case PN:
  1004.         /*
  1005.          *   page number
  1006.          *
  1007.          *   .pn N
  1008.          */
  1009.         val = getval (p, &argtyp);
  1010.         tmp = pg.curpag;
  1011.         set (&pg.curpag, val - 1, argtyp, tmp, -HUGE, HUGE);
  1012.         pg.newpag = pg.curpag + 1;
  1013.         set_ireg ("%", pg.newpag, 0);
  1014.         break;
  1015.     case PO:
  1016.         /*
  1017.          *   page offset
  1018.          *
  1019.          *   .po N
  1020.          */
  1021.         val = getval (p, &argtyp);
  1022.         set (&pg.offset, val, argtyp, 0, 0, HUGE);
  1023.         set_ireg (".o", pg.offset, 0);
  1024.         break;
  1025.     case PS:
  1026.         /*
  1027.          *   point size (IGNORED)
  1028.          *
  1029.          *   .ps +/-N
  1030.          */
  1031.         break;
  1032.     case RR:
  1033.         /*
  1034.          *   unset number reg
  1035.          *
  1036.          *   .rr R
  1037.          */
  1038.         val = getval (p, &argtyp);
  1039.         p = skipwd (p);
  1040.         p = skipbl (p);
  1041.         if (!isalpha (*p))
  1042.         {
  1043.             fprintf (err_stream,
  1044.                 "***%s: invalid or missing number register name\n",
  1045.                 myname);
  1046.         }
  1047.         else
  1048.         {
  1049.             indx = tolower (*p) - 'a';
  1050.             val = 0;
  1051.             set (&dc.nr[indx], val, argtyp, 0, -HUGE, HUGE);
  1052.         }
  1053.         break;
  1054.     case SO:
  1055.         /*
  1056.          *   source file
  1057.          *
  1058.          *   .so name
  1059.          */
  1060.         val = getval (p, &argtyp);
  1061.         p = skipwd (p);
  1062.         p = skipbl (p);
  1063.         if (getwrd (p, name) == 0)
  1064.             break;
  1065.         if (dc.flevel + 1 >= Nfiles)
  1066.         {
  1067.             fprintf (err_stream,
  1068.                 "***%s: .so commands nested too deeply\n",
  1069.                 myname);
  1070.             err_exit (-1);
  1071.         }
  1072.         if ((sofile[dc.flevel + 1] = fopen (name, "r")) == NULL_FPTR)
  1073.         {
  1074.             fprintf (err_stream,
  1075.                 "***%s: unable to open %s\n", myname, name);
  1076.             err_exit (-1);
  1077.         }
  1078.         dc.flevel += 1;
  1079.         break;
  1080.     case SP:
  1081.         /*
  1082.          *   space
  1083.          *
  1084.          *   .sp [N=1]
  1085.          */
  1086.         val = getval (p, &argtyp);
  1087.         set (&spval, val, argtyp, 1, 0, HUGE);
  1088.         space (spval);
  1089.         break;
  1090.     case SS:
  1091.         /*
  1092.          *   space char size (IGNORED)
  1093.          *
  1094.          *   .ss N
  1095.          */
  1096.         break;
  1097.     case TI:
  1098.         /*
  1099.          *   temporary indent
  1100.          *
  1101.          *   .ti [+/-N]
  1102.          */
  1103.         val = getval (p, &argtyp);
  1104.         robrk ();
  1105.         set (&dc.tival, val, argtyp, 0, 0, dc.rmval);
  1106.         break;
  1107.     case UL:
  1108.         /*
  1109.          *   underline
  1110.          *
  1111.          *   .ul [N]
  1112.          */
  1113.         val = getval (p, &argtyp);
  1114.         set (&dc.ulval, val, argtyp, 0, 1, HUGE);
  1115.         dc.cuval = dc.boval = 0;
  1116.         break;
  1117.     }
  1118. }
  1119.  
  1120.  
  1121.  
  1122.  
  1123.  
  1124. /*------------------------------*/
  1125. /*    comtyp            */
  1126. /*------------------------------*/
  1127. comtyp (p, m)
  1128. register char  *p;
  1129. char           *m;
  1130. {
  1131.  
  1132. /*
  1133.  *    decodes nro command and returns its associated value.
  1134.  *    ptr "p" is incremented (and returned)
  1135.  */
  1136.  
  1137.     register char    c1;
  1138.     register char    c2;
  1139.     char           *s;
  1140.     char        macnam[MNLEN];
  1141.  
  1142.     /*
  1143.      *   quick check: if null, ignore
  1144.      */
  1145.     if (*p == EOS)
  1146.         return (COMMENT);
  1147.  
  1148.     /*
  1149.      *   skip past dot and any whitespace
  1150.      */
  1151.     p++;
  1152.     while (*p && (*p == ' ' || *p == '\t'))
  1153.         p++;
  1154.     if (*p == '\0')
  1155.         return (COMMENT);
  1156.  
  1157.     /* 
  1158.      *   First check to see if the command is a macro. If it is,
  1159.      *   truncate to two characters and return expansion in m
  1160.      *   (i.e. the text of the macro). Note that upper and lower
  1161.      *   case characters are handled differently.
  1162.      */
  1163.     getwrd (p, macnam);
  1164.     macnam[2] = EOS;
  1165.     if ((s = getmac (macnam)) != NULL_CPTR)
  1166.     {
  1167.         strcpy (m, s);
  1168.         return (MACRO);
  1169.     }
  1170.     c1 = *p++;
  1171.     c2 = *p;
  1172.     if (c1 == '\\' && c2 == '\"')        return (COMMENT);
  1173.     if (c1 == 'a' && c2 == 'd')        return (AD);
  1174.     if (c1 == 'a' && c2 == 'f')        return (AF);
  1175.     if (c1 == 'b' && c2 == 'd')        return (BD);
  1176.     if (c1 == 'b' && c2 == 'o')        return (BO);
  1177.     if (c1 == 'b' && c2 == 'p')        return (BP);
  1178.     if (c1 == 'b' && c2 == 'r')        return (BR);
  1179.     if (c1 == 'b' && c2 == 's')        return (BS);
  1180.     if (c1 == 'c' && c2 == '2')        return (C2);
  1181.     if (c1 == 'c' && c2 == 'c')        return (CC);
  1182.     if (c1 == 'c' && c2 == 'e')        return (CE);
  1183.     if (c1 == 'c' && c2 == 's')        return (CS);
  1184.     if (c1 == 'c' && c2 == 'u')        return (CU);
  1185.     if (c1 == 'd' && c2 == 'e')        return (DE);
  1186.     if (c1 == 'd' && c2 == 's')        return (DS);
  1187.     if (c1 == 'e' && c2 == 'c')        return (EC);
  1188.     if (c1 == 'e' && c2 == 'f')        return (EF);
  1189.     if (c1 == 'e' && c2 == 'h')        return (EH);
  1190.     if (c1 == 'e' && c2 == 'n')        return (EN);
  1191.     if (c1 == '.')                return (EN);
  1192.     if (c1 == 'e' && c2 == 'o')        return (EO);
  1193.     if (c1 == 'e' && c2 == 'x')        return (EX);
  1194.     if (c1 == 'f' && c2 == 'i')        return (FI);
  1195.     if (c1 == 'f' && c2 == 'l')        return (FL);
  1196.     if (c1 == 'f' && c2 == 'o')        return (FO);
  1197.     if (c1 == 'f' && c2 == 't')        return (FT);
  1198.     if (c1 == 'h' && c2 == 'e')        return (HE);
  1199.     if (c1 == 'i' && c2 == 'f')        return (IF);
  1200. /*    if (c1 == 'i' && c2 == 'e')        return (IE);*/
  1201. /*    if (c1 == 'e' && c2 == 'l')        return (EL);*/
  1202.     if (c1 == 'i' && c2 == 'g')        return (IG);
  1203.     if (c1 == 'i' && c2 == 'n')        return (IN);
  1204.     if (c1 == 'j' && c2 == 'u')        return (JU);
  1205.     if (c1 == 'l' && c2 == 'g')        return (LG);
  1206.     if (c1 == 'l' && c2 == 'l')        return (LL);
  1207.     if (c1 == 'l' && c2 == 's')        return (LS);
  1208.     if (c1 == 'l' && c2 == 't')        return (LT);
  1209.     if (c1 == 'm' && c2 == '1')        return (M1);
  1210.     if (c1 == 'm' && c2 == '2')        return (M2);
  1211.     if (c1 == 'm' && c2 == '3')        return (M3);
  1212.     if (c1 == 'm' && c2 == '4')        return (M4);
  1213.     if (c1 == 'm' && c2 == 'c')        return (MC);
  1214.     if (c1 == 'n' && c2 == 'a')        return (NA);
  1215.     if (c1 == 'n' && c2 == 'e')        return (NE);
  1216.     if (c1 == 'n' && c2 == 'f')        return (NF);
  1217.     if (c1 == 'n' && c2 == 'j')        return (NJ);
  1218.     if (c1 == 'n' && c2 == 'r')        return (NR);
  1219.     if (c1 == 'o' && c2 == 'f')        return (OF);
  1220.     if (c1 == 'o' && c2 == 'h')        return (OH);
  1221.     if (c1 == 'p' && c2 == 'c')        return (PC);
  1222.     if (c1 == 'p' && c2 == 'l')        return (PL);
  1223.     if (c1 == 'p' && c2 == 'm')        return (PM);
  1224.     if (c1 == 'p' && c2 == 'n')        return (PN);
  1225.     if (c1 == 'p' && c2 == 'o')        return (PO);
  1226.     if (c1 == 'p' && c2 == 's')        return (PS);
  1227.     if (c1 == 'r' && c2 == 'm')        return (RM);
  1228.     if (c1 == 'r' && c2 == 'r')        return (RR);
  1229.     if (c1 == 's' && c2 == 'o')        return (SO);
  1230.     if (c1 == 's' && c2 == 'p')        return (SP);
  1231.     if (c1 == 's' && c2 == 's')        return (SS);
  1232.     if (c1 == 't' && c2 == 'i')        return (TI);
  1233.     if (c1 == 't' && c2 == 'l')        return (TL);
  1234.     if (c1 == 'u' && c2 == 'l')        return (UL);
  1235.  
  1236.     if (c1 == 't' && c2 == 'r')        return (TR);
  1237.     if (c1 == 'f' && c2 == 'c')        return (FC);
  1238.  
  1239.     return (UNKNOWN);
  1240. }
  1241.  
  1242.  
  1243.  
  1244.  
  1245.  
  1246. /*------------------------------*/
  1247. /*    gettl            */
  1248. /*------------------------------*/
  1249. gettl (p, q, limit)
  1250. register char  *p;
  1251. register char  *q;
  1252. int           *limit;
  1253. {
  1254.  
  1255. /*
  1256.  *    get header or footer title
  1257.  */
  1258.  
  1259.     /*
  1260.      *   skip forward a word...
  1261.      */
  1262.     p = skipwd (p);
  1263.     p = skipbl (p);
  1264.  
  1265.     /*
  1266.      *   copy and set limits
  1267.      */
  1268.     strcpy (q, p);
  1269.     limit[LEFT]  = dc.inval;
  1270.     limit[RIGHT] = dc.rmval;
  1271. }
  1272.  
  1273.  
  1274.  
  1275.  
  1276.  
  1277. /*------------------------------*/
  1278. /*    getval            */
  1279. /*------------------------------*/
  1280. getval (p, p_argtyp)
  1281. register char  *p;
  1282. register char  *p_argtyp;
  1283. {
  1284.  
  1285. /*
  1286.  *    retrieves optional argument following command.
  1287.  *    returns positive integer value with sign (if any)
  1288.  *    saved in character addressed by p_argt.
  1289.  */
  1290.  
  1291.     p = skipwd (p);
  1292.     p = skipbl (p);
  1293.     *p_argtyp = *p;
  1294.     if ((*p == '+') || (*p == '-'))
  1295.         ++p;
  1296.     return (ctod (p));
  1297. }
  1298.  
  1299.  
  1300.  
  1301.  
  1302.  
  1303. /*------------------------------*/
  1304. /*    getnumeric        */
  1305. /*------------------------------*/
  1306.  
  1307. #define N_ADD            0
  1308. #define N_SUB            1
  1309. #define N_MUL            2
  1310. #define N_DIV            3
  1311. #define N_MOD            4
  1312. #define N_LT            5
  1313. #define N_GT            6
  1314. #define N_LE            7
  1315. #define N_GE            8
  1316. #define N_EQ            9
  1317. #define N_AND            10
  1318. #define N_OR            11
  1319.  
  1320.  
  1321. getnumeric (p)
  1322. register char  *p;
  1323. {
  1324.  
  1325. /*
  1326.  *    retrieves numeric argument. will parse for number registers,
  1327.  *    constants, operations, and logical comparisons. no imbeded spaces!
  1328.  *    start at p (don't skip)
  1329.  */
  1330.  
  1331.     char        name[10];
  1332.     int        val;
  1333.     int        thisval;
  1334.     int        autoinc;
  1335.     char        buf[256];
  1336.     char           *pbuf;
  1337.     int        next_op;
  1338.     int        nreg;
  1339.  
  1340.     val     = 0;
  1341.     next_op = N_ADD;
  1342.     while (*p != EOS && !isspace (*p))
  1343.     {
  1344.         if (!strncmp (p, "\\n", 2))
  1345.         {
  1346.             if (debugging)
  1347.                 fprintf (err_stream,
  1348.                 "***%s.getnumeric: found number reg...\n",myname);
  1349.             /*
  1350.              *   number register
  1351.              */
  1352.             autoinc = 0;
  1353.             p += 2;
  1354.             if (*p == '+')
  1355.             {
  1356.                 autoinc = 1;
  1357.                 p++;
  1358.             }
  1359.             else if (*p == '-')
  1360.             {
  1361.                 autoinc = -1;
  1362.                 p++;
  1363.             }
  1364.             if (isalpha (*p))
  1365.             {
  1366.                 /*
  1367.                  *   \nx form. find reg (a-z)
  1368.                  */
  1369.                 nreg = tolower (*p) - 'a';
  1370.                 p++;
  1371.  
  1372.                 /*
  1373.                  *   was this \n+x or \n-x? if so, do the
  1374.                  *   auto incr
  1375.                  */
  1376.                 if (autoinc > 0)
  1377.                     dc.nr[nreg] += dc.nrauto[nreg];
  1378.                 else if (autoinc < 0)
  1379.                     dc.nr[nreg] -= dc.nrauto[nreg];
  1380.  
  1381.  
  1382.                 val = do_oper (val, next_op, dc.nr[nreg]);
  1383.             }
  1384.             else if (*p == '%')
  1385.             {
  1386.                 /*
  1387.                  *   \n% form. find index into reg struct
  1388.                  */
  1389.                 nreg = findreg ("%");
  1390.                 p++;
  1391.                 if (nreg < 0)
  1392.                 {
  1393.                     fprintf (err_stream,
  1394.                         "***%s: no register match\n",
  1395.                         myname);
  1396.                     err_exit (-1);
  1397.                 }
  1398.  
  1399.                 /*
  1400.                  *   was this \n+% or \n-%? if so, do the
  1401.                  *   auto incr
  1402.                  */
  1403.                 if (autoinc > 0)
  1404.                     rg[nreg].rval += rg[nreg].rauto;
  1405.                 else if (autoinc < 0)
  1406.                     rg[nreg].rval -= rg[nreg].rauto;
  1407.  
  1408.  
  1409.                 val = do_oper (val, next_op, rg[nreg].rval);
  1410.             }
  1411.             else if (*p == '(')
  1412.             {
  1413.                 /*
  1414.                  *   \n(xx form. find index into reg struct
  1415.                  */
  1416.                 p++;
  1417.                 name[0] = *p++;
  1418.                 name[1] = *p++;
  1419.                 if (name[1] == ' '  || name[1] == '\t'
  1420.                 ||  name[1] == '\n' || name[1] == '\r')
  1421.                     name[1] = '\0';
  1422.                 name[2] = '\0';
  1423.                 nreg = findreg (name);
  1424.                 if (nreg < 0)
  1425.                 {
  1426.                     fprintf (err_stream,
  1427.                         "***%s: no register match\n",
  1428.                         myname);
  1429.                     err_exit (-1);
  1430.                 }
  1431.                 
  1432.  
  1433.                 /*
  1434.                  *   was this \n+(xx or \n-(xx? if so, do the
  1435.                  *   auto incr
  1436.                  */
  1437.                 if (rg[nreg].rflag & RF_WRITE)
  1438.                 {
  1439.                     if (autoinc > 0)
  1440.                         rg[nreg].rval += rg[nreg].rauto;
  1441.                     else if (autoinc < 0)
  1442.                         rg[nreg].rval -= rg[nreg].rauto;
  1443.                 }
  1444.  
  1445.                 val = do_oper (val, next_op, rg[nreg].rval);
  1446.             }
  1447.         }
  1448.         else if (isdigit (*p))
  1449.         {
  1450.             pbuf = buf;
  1451.             while (1)
  1452.             {
  1453.                 if (*p == EOS || isspace (*p))
  1454.                     break;
  1455.                 if (*p == '\\')
  1456.                     break;
  1457.                 if (iscond (*p))
  1458.                     break;
  1459.                 if (isoper (*p))
  1460.                     break;
  1461.  
  1462.                 *pbuf++ = *p++;
  1463.             }
  1464.             *pbuf = EOS;
  1465.  
  1466.             if (debugging)
  1467.                 fprintf (err_stream,
  1468.                 "***%s.getnumeric: buf:|%s| next_op:%d val:%d\n",
  1469.                 myname,buf,next_op,val);
  1470.  
  1471.             thisval = ctod (buf);
  1472.             val     = do_oper (val, next_op, thisval);
  1473.             if (debugging)
  1474.                 fprintf (err_stream,
  1475.                 "***%s.getnumeric: thisval:%d val:%d\n",
  1476.                 myname,thisval,val);
  1477.         }
  1478.  
  1479.         /*
  1480.          *   p should now be at the next thing, either a
  1481.          *   space, a null, or an operator
  1482.          */
  1483.         if (*p == EOS || isspace (*p))
  1484.             break;
  1485.         switch (*p)
  1486.         {
  1487.         case '+':
  1488.             next_op = N_ADD;
  1489.             p++;
  1490.             break;
  1491.         case '-':
  1492.             next_op = N_SUB;
  1493.             p++;
  1494.             break;
  1495.         case '*':
  1496.             next_op = N_MUL;
  1497.             p++;
  1498.             break;
  1499.         case '/':
  1500.             next_op = N_DIV;
  1501.             p++;
  1502.             break;
  1503.         case '%':
  1504.             next_op = N_MOD;
  1505.             p++;
  1506.             break;
  1507.         case '&':
  1508.             next_op = N_AND;
  1509.             p++;
  1510.             break;
  1511.         case ':':
  1512.             next_op = N_OR;
  1513.             p++;
  1514.             break;
  1515.         case '<':
  1516.             p++;
  1517.             if (*p == '=')
  1518.             {
  1519.                 p++;
  1520.                 next_op = N_LE;
  1521.             }
  1522.             else
  1523.                 next_op = N_LT;
  1524.             break;
  1525.         case '>':
  1526.             p++;
  1527.             if (*p == '=')
  1528.             {
  1529.                 p++;
  1530.                 next_op = N_GE;
  1531.             }
  1532.             else
  1533.                 next_op = N_GT;
  1534.             break;
  1535.         case '=':
  1536.             p++;
  1537.             if (*p == '=')
  1538.                 p++;
  1539.             next_op = N_EQ;
  1540.             break;
  1541.         }
  1542.     }
  1543.     return (val);
  1544. }
  1545.  
  1546.  
  1547.  
  1548.  
  1549.  
  1550. /*------------------------------*/
  1551. /*    do_oper            */
  1552. /*------------------------------*/
  1553. do_oper (first, oper, second)
  1554. int    first;
  1555. int    oper;
  1556. int    second;
  1557. {
  1558.     int    val;
  1559.     
  1560.     if (debugging)
  1561.         fprintf (err_stream,
  1562.             "***%s.do_oper: first:%d op:%d second:%d\n",
  1563.             myname, first, oper, second);
  1564.  
  1565.     switch (oper)
  1566.     {
  1567.     case N_ADD:
  1568.         val = first + second;
  1569.         break;
  1570.     case N_SUB:
  1571.         val = first - second;
  1572.         break;
  1573.     case N_MUL:
  1574.         val = first * second;
  1575.         break;
  1576.     case N_DIV:
  1577.         val = first / second;
  1578.         break;
  1579.     case N_MOD:
  1580.         val = first % second;
  1581.         break;
  1582.     case N_LT:
  1583.         val = ((first < second) ? 1 : 0);
  1584.         break;
  1585.     case N_GT:
  1586.         val = ((first > second) ? 1 : 0);
  1587.         break;
  1588.     case N_LE:
  1589.         val = ((first <= second) ? 1 : 0);
  1590.         break;
  1591.     case N_GE:
  1592.         val = ((first >= second) ? 1 : 0);
  1593.         break;
  1594.     case N_EQ:
  1595.         val = ((first == second) ? 1 : 0);
  1596.         break;
  1597.     case N_AND:
  1598.         val = ((first && second) ? 1 : 0);
  1599.         break;
  1600.     case N_OR:
  1601.         val = ((first || second) ? 1 : 0);
  1602.         break;
  1603.     }
  1604.  
  1605.     return (val);
  1606. }
  1607.  
  1608.  
  1609.  
  1610.  
  1611.  
  1612. /*------------------------------*/
  1613. /*    set            */
  1614. /*------------------------------*/
  1615. set (param, val, type, defval, minval, maxval)
  1616. register int   *param;
  1617. register int    val;
  1618. register char    type;
  1619. register int    defval;
  1620. register int    minval;
  1621. register int    maxval;
  1622. {
  1623.  
  1624. /*
  1625.  *    set parameter and check range. this is for basically all commands
  1626.  *    which take interger args
  1627.  *
  1628.  *    no param (i.e. \r or \n) means reset default
  1629.  *    + means param += val (increment)
  1630.  *    - means param -= val (decrement)
  1631.  *    anything else makes an assignment within the defined numerical limits
  1632.  *
  1633.  *    examples:
  1634.  *
  1635.  *    .nr a 14    set register 'a' to 14
  1636.  *    .nr a +1    increment register 'a' by 1
  1637.  *    .nr a        reset register 'a' to default value (0)
  1638.  */
  1639.  
  1640.     switch (type)
  1641.     {
  1642.     case '\r': 
  1643.     case '\n': 
  1644.         *param = defval;
  1645.         break;
  1646.     case '+': 
  1647.         *param += val;
  1648.         break;
  1649.     case '-': 
  1650.         *param -= val;
  1651.         break;
  1652.     default: 
  1653.         *param = val;
  1654.         break;
  1655.     }
  1656.     *param = min (*param, maxval);
  1657.     *param = max (*param, minval);
  1658. }
  1659.  
  1660.  
  1661.  
  1662.  
  1663.  
  1664. /*------------------------------*/
  1665. /*    set_ireg        */
  1666. /*------------------------------*/
  1667. set_ireg (name, val, opt)
  1668. register char  *name;
  1669. register int    val;
  1670. register int    opt;                /* 0=internal, 1=user set */
  1671. {
  1672.  
  1673. /*
  1674.  *    set internal register "name" to val. ret 0 if ok, else -1 if reg not
  1675.  *    found or 1 if read only
  1676.  */
  1677.  
  1678.     register int    nreg;
  1679.  
  1680.     nreg = findreg (name);
  1681.     if (nreg < 0)
  1682.         return (-1);
  1683.  
  1684.     if ((rg[nreg].rflag & RF_WRITE) || (opt == 0))
  1685.     {
  1686.         rg[nreg].rval = val;
  1687.  
  1688.         return (0);
  1689.     }
  1690.  
  1691.     return (1);
  1692. }
  1693.  
  1694.  
  1695.  
  1696.  
  1697.  
  1698. /*------------------------------*/
  1699. /*    read_if            */
  1700. /*------------------------------*/
  1701. read_if ()
  1702. {
  1703.  
  1704. /*
  1705.  *    read input while in if statement. stop when a line starts with \}
  1706.  */
  1707.  
  1708.     char    ibuf[MAXLINE];
  1709.     char   *pp;
  1710.  
  1711.     while (getlin (ibuf, sofile[dc.flevel]) != EOF)
  1712.     {
  1713.         if (debugging)
  1714.             fprintf (err_stream,
  1715.             "***%s.read_if: ibuf=|%s|\n",myname,ibuf);
  1716.  
  1717.         pp = skipbl (ibuf);
  1718.         if (*pp == '\\' && *(pp+1) == '}')
  1719.             return;
  1720.  
  1721.         /*
  1722.          *   if line is a command or text
  1723.          */
  1724.         if (ibuf[0] == dc.cmdchr)
  1725.         {
  1726.              comand (ibuf);
  1727.         }
  1728.         else
  1729.         {
  1730.             /*
  1731.              *   this is a text line. first see if
  1732.              *   first char is space. if it is, break
  1733.              *   line.
  1734.              */
  1735.             if (ibuf[0] == ' ')
  1736.                 robrk ();
  1737.             text (ibuf);
  1738.         }
  1739.  
  1740.         pp = ibuf;
  1741.         while (*pp != EOS)
  1742.         {
  1743.             if (*pp == '\\' && *(pp+1) == '}')
  1744.                 return;
  1745.         }
  1746.     }
  1747. }
  1748.